package com.xhj.mybatis.mapping;

import com.xhj.mybatis.session.Configuration;
import com.xhj.mybatis.type.JdbcType;
import com.xhj.mybatis.type.TypeHandler;
import com.xhj.mybatis.type.TypeHandlerRegistry;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

/**
 * ResultMapping
 *
 * @author XJks
 * @description 结果映射类，用于描述数据库查询结果与 Java 对象属性之间的映射关系。与 {@link ParameterMapping} 作用类似，
 */
public class ResultMapping {

    /**
     * MyBatis的全局配置对象
     */
    private Configuration configuration;

    /**
     * Java对象的属性名
     */
    private String property;

    /**
     * 数据库表的列名
     */
    private String column;

    /**
     * Java属性的数据类型
     */
    private Class<?> javaType;

    /**
     * 数据库字段的JDBC类型
     */
    private JdbcType jdbcType;

    /**
     * 类型处理器，用于Java类型和JDBC类型之间的转换
     */
    private TypeHandler<?> typeHandler;

    /**
     * 不能为空的列集合
     */
    private Set<String> notNullColumns;

    /**
     * 列名前缀
     */
    private String columnPrefix;

    /**
     * 结果标志列表（如ID、构造器参数等）
     */
    private List<ResultFlag> flags;

    /**
     * 私有构造方法，外部不能直接实例化
     */
    ResultMapping() {
    }

    /**
     * 构建器模式，方便链式设置属性
     */
    public static class Builder {
        /**
         * 内部持有一个ResultMapping对象
         */
        private ResultMapping resultMapping = new ResultMapping();

        /**
         * 构造方法，指定配置、属性名、列名和类型处理器
         *
         * @param configuration Mybatis配置对象
         * @param property      Java对象的属性名
         * @param column        数据库表的列名
         * @param typeHandler   类型处理器
         */
        public Builder(Configuration configuration, String property, String column, TypeHandler<?> typeHandler) {
            this(configuration, property);
            resultMapping.column = column;
            resultMapping.typeHandler = typeHandler;
        }

        /**
         * 构造方法，指定配置、属性名、列名和Java类型
         *
         * @param configuration Mybatis配置对象
         * @param property      Java对象的属性名
         * @param column        数据库表的列名
         * @param javaType      Java属性的数据类型
         */
        public Builder(Configuration configuration, String property, String column, Class<?> javaType) {
            this(configuration, property);
            resultMapping.column = column;
            resultMapping.javaType = javaType;
        }

        /**
         * 构造方法，指定配置和属性名
         *
         * @param configuration Mybatis配置对象
         * @param property      Java对象的属性名
         */
        public Builder(Configuration configuration, String property) {
            resultMapping.configuration = configuration;
            resultMapping.property = property;
            // 初始化标志列表
            resultMapping.flags = new ArrayList<>();
        }

        /**
         * 设置Java类型
         *
         * @param javaType Java属性的数据类型
         * @return Builder对象，方便链式调用
         */
        public Builder javaType(Class<?> javaType) {
            resultMapping.javaType = javaType;
            return this;
        }

        /**
         * 设置JDBC类型
         *
         * @param jdbcType 数据库字段的JDBC类型
         * @return Builder对象，方便链式调用
         */
        public Builder jdbcType(JdbcType jdbcType) {
            resultMapping.jdbcType = jdbcType;
            return this;
        }

        /**
         * 设置列名
         *
         * @param column 数据库表的列名
         * @return Builder对象，方便链式调用
         */
        public Builder column(String column) {
            resultMapping.column = column;
            return this;
        }

        /**
         * 设置不能为空的列集合
         *
         * @param notNullColumns 不能为空的列集合
         * @return Builder对象，方便链式调用
         */
        public Builder notNullColumns(Set<String> notNullColumns) {
            resultMapping.notNullColumns = notNullColumns;
            return this;
        }

        /**
         * 设置列名前缀
         *
         * @param columnPrefix 列名前缀
         * @return Builder对象，方便链式调用
         */
        public Builder columnPrefix(String columnPrefix) {
            resultMapping.columnPrefix = columnPrefix;
            return this;
        }

        /**
         * 设置结果标志列表
         *
         * @param flags 结果标志列表
         * @return Builder对象，方便链式调用
         */
        public Builder flags(List<ResultFlag> flags) {
            resultMapping.flags = flags;
            return this;
        }

        /**
         * 设置类型处理器
         *
         * @param typeHandler 类型处理器
         * @return Builder对象，方便链式调用
         */
        public Builder typeHandler(TypeHandler<?> typeHandler) {
            resultMapping.typeHandler = typeHandler;
            return this;
        }

        /**
         * 构建ResultMapping对象
         *
         * @return 构建好的ResultMapping对象
         */
        public ResultMapping build() {
            // 将集合变为不可修改，防止外部更改
            resultMapping.flags = Collections.unmodifiableList(resultMapping.flags);
            // 解析类型处理器
            resolveTypeHandler();
            // 校验参数合法性
            validate();
            return resultMapping;
        }

        /**
         * 校验参数是否合法
         */
        private void validate() {
            // todo:源码对嵌套映射等存在校验逻辑，这里暂不实现。
        }

        /**
         * 解析类型处理器
         */
        private void resolveTypeHandler() {
            // 如果没有设置类型处理器，但有Java类型，则从注册表获取
            if (resultMapping.typeHandler == null && resultMapping.javaType != null) {
                Configuration configuration = resultMapping.configuration;
                TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
                resultMapping.typeHandler = typeHandlerRegistry.getTypeHandler(resultMapping.javaType, resultMapping.jdbcType);
            }
        }
    }

    /**
     * 获取属性名
     *
     * @return 属性名
     */
    public String getProperty() {
        return property;
    }

    /**
     * 获取列名
     *
     * @return 列名
     */
    public String getColumn() {
        return column;
    }

    /**
     * 获取Java类型
     *
     * @return Java类型
     */
    public Class<?> getJavaType() {
        return javaType;
    }

    /**
     * 获取JDBC类型
     *
     * @return JDBC类型
     */
    public JdbcType getJdbcType() {
        return jdbcType;
    }

    /**
     * 获取类型处理器
     *
     * @return 类型处理器
     */
    public TypeHandler<?> getTypeHandler() {
        return typeHandler;
    }

    /**
     * 获取不能为空的列集合
     *
     * @return 不能为空的列集合
     */
    public Set<String> getNotNullColumns() {
        return notNullColumns;
    }

    /**
     * 获取列名前缀
     *
     * @return 列名前缀
     */
    public String getColumnPrefix() {
        return columnPrefix;
    }

    /**
     * 获取结果标志列表
     *
     * @return 结果标志列表
     */
    public List<ResultFlag> getFlags() {
        return flags;
    }

}
